﻿using System;
using System.Windows.Forms;
using Map;
using Map_Creator.MapInfo;
using Map_Creator.Painters;
using Map_Creator.RedoUndo.Actions;
using Map_Creator.XNA;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Size = System.Drawing.Size;

namespace Map_Creator.MainForm.Controls
{
    public partial class AnimatedTilesPanel : GraphicsDeviceControl
    {
        private DataPainter DataPainter;

        public bool IsDrawGrid = true;

        public AnimatedTilesPanel()
        {
            InitializeComponent();

            TileSet.PrimaryTileSetChanged += TileSet_PrimaryTileSetChanged;
            TileSet.SelectedDataGridChanged += TileSet_SelectedDataGridChanged;
        }

        protected override void Draw(PaintEventArgs e)
        {   
            if (MapInfo.Map.SelectedMap == null) return;
            if (MapInfo.Map.SelectedMap.CurrentTileSet == null) return;

            var left = e.ClipRectangle.Left / MapInfo.Map.SelectedMap.TileSize;
            var top = e.ClipRectangle.Top / MapInfo.Map.SelectedMap.TileSize;
            var right = (int)Math.Ceiling(e.ClipRectangle.Right / (float)(MapInfo.Map.SelectedMap.TileSize));
            var bottom = (int)Math.Ceiling(e.ClipRectangle.Bottom / (float)(MapInfo.Map.SelectedMap.TileSize));

            var tilesRectangle = new Rectangle(left, top, right - left, bottom - top);
            var tileSize = MapInfo.Map.SelectedMap.TileSize;
            var realClipRect = new Rectangle(left * tileSize, top * tileSize, (right - left) * tileSize, (bottom - top) * tileSize);

            xnaGraphics.Begin();
            xnaGraphics.FillRectangle(realClipRect, Color.FromNonPremultiplied(BackColor.R, BackColor.G, BackColor.B, BackColor.A));
            DrawTiles(new Point(left, top), new Point(right, bottom));

            DrawGrid(new Point(left, top), new Point(right, bottom));
   
            if (DataPainter != null)
                DataPainter.OnDraw(xnaGraphics, tilesRectangle);
            else
                MapInfo.Map.SelectedMap.CurrentTileSet.Selection.OnDraw(xnaGraphics, tilesRectangle);

            xnaGraphics.End();
        }

        void TileSet_SelectedDataGridChanged(MapInfo.Map map)
        {
            DataPainter = map.CurrentTileSet.CurrentDataGrid == null ? 
                null : 
                new DataPainter(map.CurrentTileSet.CurrentDataGrid,Services);
            Invalidate();
        }

        private void TileSet_PrimaryTileSetChanged(MapInfo.Map map)
        {
            DataPainter = null;
            if (map == null || map.CurrentTileSet == null)
            {
                Size = Size.Empty;
                if (backBuffer != null)
                {
                    backBuffer.Dispose();
                    backBuffer = null;
                }
            }
            else
            {
                var tileSet = map.CurrentTileSet;
                Size = new Size(tileSet.DefinedAnimatedTiles.Size.X * map.TileSize, tileSet.DefinedAnimatedTiles.Size.Y * map.TileSize);
                if (backBuffer != null)
                {
                    backBuffer.Dispose();
                    backBuffer = null;
                }
                backBuffer = new RenderTarget2D(GraphicsDevice, Size.Width, Size.Height, false,
                                                SurfaceFormat.Color, DepthFormat.Depth24, 0,
                                                RenderTargetUsage.PreserveContents);
            }
        }


        private void DrawGrid(Point topLeft, Point buttomRight)
        {
            if (IsDrawGrid)
            {
                for (int i = topLeft.X; i < buttomRight.X && i < MapInfo.Map.SelectedMap.CurrentTileSet.TilesSize.X; i++)
                {
                    for (int j = topLeft.Y; j < buttomRight.Y && j < MapInfo.Map.SelectedMap.CurrentTileSet.TilesSize.Y; j++)
                    {
                        xnaGraphics.DrawRectangle(new Rectangle(i * MapInfo.Map.SelectedMap.TileSize, j * MapInfo.Map.SelectedMap.TileSize,
                                                             MapInfo.Map.SelectedMap.TileSize, MapInfo.Map.SelectedMap.TileSize), Color.Multiply(Color.White, .4f));
                    }
                }
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;

            var position = e.Location;
            position.X = MathEx.Clamp(position.X, 0, Width - 1);
            position.Y = MathEx.Clamp(position.Y, 0, Height - 1);

            var tilePosition = new Point(position.X / MapInfo.Map.SelectedMap.TileSize, position.Y / MapInfo.Map.SelectedMap.TileSize);

            var invalidationRectangle = DataPainter != null ? 
                DataPainter.OnMouseDown(tilePosition, e.Button) : 
                MapInfo.Map.SelectedMap.CurrentTileSet.Selection.OnMouseDown(tilePosition, e.Button);

            if (invalidationRectangle != Rectangle.Empty)
                Invalidate(MathEx.ConvertToSystemRect(MapInfo.Map.SelectedMap.CurrentTileSet.GetScreenSize(invalidationRectangle)));
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;

            var position = e.Location;
            position.X = MathEx.Clamp(position.X, 0, Width - 1);
            position.Y = MathEx.Clamp(position.Y, 0, Height - 1);

            var tilePosition = new Point(position.X / MapInfo.Map.SelectedMap.TileSize, position.Y / MapInfo.Map.SelectedMap.TileSize);

            var invalidationRectangle = DataPainter != null ?
                DataPainter.OnMouseMove(tilePosition, e.Button) :
                MapInfo.Map.SelectedMap.CurrentTileSet.Selection.OnMouseMove(tilePosition, e.Button);

            if (invalidationRectangle != Rectangle.Empty)
                Invalidate(MathEx.ConvertToSystemRect(MapInfo.Map.SelectedMap.CurrentTileSet.GetScreenSize(invalidationRectangle)));
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            Parent.Focus();

            base.OnMouseEnter(e);
        }

        private void DrawTiles(Point topLeft, Point buttomRight)
        {
            var rect = new Rectangle(topLeft.X, topLeft.Y, buttomRight.X - topLeft.X, buttomRight.Y - topLeft.Y);
            var tileSize = MapInfo.Map.SelectedMap.TileSize;
            var tileSet = MapInfo.Map.SelectedMap.CurrentTileSet;
            for (var i = 0; i < tileSet.DefinedAnimatedTiles.Size.X; i++)
            {
                for (var j = 0; j < tileSet.DefinedAnimatedTiles.Size.Y; j++)
                {
                    var tile = tileSet.DefinedAnimatedTiles[i, j];
                    if (tile== null) continue;
                    if (rect.Contains(i,j))
                    {
                        tile.DrawTile(xnaGraphics, MapInfo.Map.SelectedMap, new Rectangle(i * tileSize, j * tileSize, tileSize, tileSize), Color.White);
                        /*var tileValue = tileSet.DefinedAnimatedTiles[i,j].Value;
                        xnaGraphics.Draw(tileSet.TilesImage,
                                        new Rectangle(i * tileSize, j * tileSize, tileSize, tileSize),
                                        new Rectangle((tileValue % tileSet.TilesSize.X) * tileSize,
                                                         (tileValue / tileSet.TilesSize.X) * tileSize,
                                                         tileSize, tileSize), Color.White);*/
                    }
                }
            }
        }

        private void OnMouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;

            var position = e.Location;
            position.X = MathEx.Clamp(position.X, 0, Width - 1);
            position.Y = MathEx.Clamp(position.Y, 0, Height - 1);

            var tilePosition = new Point(position.X / MapInfo.Map.SelectedMap.TileSize, position.Y / MapInfo.Map.SelectedMap.TileSize);

            var tileSet = MapInfo.Map.SelectedMap.CurrentTileSet;
            var animatedTileEditor = new AnimatedTileEditor.AnimatedTileEditor(tileSet,
                                                                               (AnimatedTileStruct) tileSet.DefinedAnimatedTiles[
                                                                                   tilePosition.X, tilePosition.Y]);
            var result = animatedTileEditor.ShowDialog();

            if (result == DialogResult.OK)
            {
                ActionHandler.MainActionHandler.AddActionAndExecute(new AnimatedTileChange(animatedTileEditor.TileResult,tileSet,tilePosition));
            }
        }
    }
}